package org.example.controller;

import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.example.config.WeChatPayConfig;
import org.example.enums.ProductOrderEnum;
import org.example.service.ProductOrderService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @description:
 * @author: 谢超
 * @date: 2024/8/26 16:07
 */
@Controller
@Slf4j
@RequestMapping("/api/callback/order/v1")
public class PayCallbackController {

    @Resource
    private WeChatPayConfig weChatPayConfig;

    @Resource
    private ProductOrderService productOrderService;

//    @Resource
//    private ScheduledUpdateCertificatesVerifier verifier;

    /**
     * 获取报文
     * 验证签名（确保微信传输过来的）
     * 解密（AES对称解密出原始数据）
     * 处理业务逻辑
     * 响应请求
     * @param request
     * @param response
     * @return
     */
    @ResponseBody
    @RequestMapping("wechat")
    public Map<String, String> wechatPayCallback(HttpServletRequest request, HttpServletResponse response) {
        // 获取请求报文,这里是个流，需要特殊处理
        String requestBody = getRequestBodyByStream(request);

        //随机串
        String nonceStr = request.getHeader("Wechatpay-Nonce");

        //微信传递过来的签名
        String signature = request.getHeader("Wechatpay-Signature");

        //证书序列号（微信平台）
        String serialNo = request.getHeader("Wechatpay-Serial");

        //时间戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");

        // 构造签名串
        String signStr = Stream.of(timestamp, nonceStr, requestBody).collect(Collectors.joining("\n", "", "\n"));

        Map<String, String> map = new HashMap<>(2);

        try {
            // 验证签名是否通过
            boolean sign = verifiedSign(serialNo, signStr, signature);

            if (sign) {
                // 解密数据
                String data = decrytData(requestBody);
                log.info("解密后的数据:{}", data);

                Map<String, String> paramsMap = convertWechatPayMsgToMap(data);

                // 处理业务逻辑 TODO
                productOrderService.processOrderCallBackMsg(ProductOrderEnum.WECHAT_PAY.name(), paramsMap);

                // 响应微信
                map.put("code", "SUCCESS");
                map.put("message", "成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("微信支付回调异常:{}", e.getMessage());
        }

        return map;

    }

    /**
     * 转换body为map
     * @param plainBody
     * @return
     */
    private Map<String, String> convertWechatPayMsgToMap(String plainBody) {
        Map<String, String> paramMap = new HashMap<>(2);

        JSONObject jsonObject = JSONObject.parseObject(plainBody);

        paramMap.put("out_trade_no", jsonObject.getString("out_trade_no"));
        paramMap.put("trade_state", jsonObject.getString("trade_state"));
        // jsonObject.getJSONObject拿的是json对象中的对象key属性，这样可以拿其中的属性
        paramMap.put("account_no", jsonObject.getJSONObject("attach").getString("accountNo"));

        return paramMap;
    }

    /**
     * 解密body的密文
     * @param body
     * @return
     */
    private String decrytData(String body) throws UnsupportedEncodingException, GeneralSecurityException {
        AesUtil aesUtil = new AesUtil(weChatPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));

        JSONObject object = JSONObject.parseObject(body);
        JSONObject resource = object.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String associatedData = resource.getString("associated_data");
        String nonce = resource.getString("nonce");

        return aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
    }

    /**
     * 验证签名
     * @param serialNo  微信平台-证书序列号
     * @param signStr   自己组装的签名串
     * @param signature 微信返回的签名
     * @return
     */
    private boolean verifiedSign(String serialNo, String signStr, String signature) {
//        return verifier.verify(serialNo, signStr.getBytes(StandardCharsets.UTF_8), signature);
        return false;
    }

    /**
     * 读取流
     * @param request
     * @return
     */
    private String getRequestBodyByStream(HttpServletRequest request) {
        StringBuffer stringBuffer = new StringBuffer();
        try(ServletInputStream inputStream = request.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuffer.append(line);
            }
        } catch (IOException e) {
            log.error("流获取失败", e);
        }
        return stringBuffer.toString();
    }
}
